import gc
from machine import SPI, Pin, Timer
import st7789
import utime
import urandom

# 硬件初始化
spi = SPI(0, baudrate=40000000, polarity=1, phase=0, bits=8, endia=0, sck=Pin(6), mosi=Pin(8))
display = st7789.ST7789(spi, 240, 240, reset=Pin(11, func=Pin.GPIO, dir=Pin.OUT), dc=Pin(7, func=Pin.GPIO, dir=Pin.OUT))
display.init()
utime.sleep(1)
display.fill(st7789.color565(0,0,0))

# 引脚初始化
pinArray = [Pin(2, Pin.OUT), Pin(1, Pin.OUT), Pin(0, Pin.OUT)]
# 按钮初始化
LEFT = Pin(10, Pin.IN)    # 按下0
RIGHT = Pin(9, Pin.IN)    # 按下0
UP = Pin(14, Pin.IN)      # 按下1
DOWN = Pin(13, Pin.IN)    # 按下1
TEMP = Pin(5, Pin.IN)     # 按下1

# 启用下拉电阻
for pin in [LEFT, RIGHT, UP, DOWN, TEMP]:
    pin.pull(Pin.PULL_DOWN)

# 颜色常量
BLACK = st7789.color565(0, 0, 0)
WHITE = st7789.WHITE

# 通用函数
def draw_menu(title, options, selection, exit_option=True):
    display.fill(BLACK)
    display.draw_string(25, 20, title, color=WHITE, bg=BLACK, size=4)
    
    for i, option in enumerate(options):
        x = 60 + i * 60
        if i == selection:
            display.fill_rect(x-10, 95, 40, 40, WHITE)
            display.draw_string(x, 100, option, color=BLACK, size=4)
        else:
            display.draw_string(x, 100, option, color=WHITE, size=4)
    
    if exit_option:
        y = 170
        if selection == len(options):
            display.fill_rect(90, y, 60, 30, WHITE)
            display.draw_string(100, y, "OUT", color=BLACK, size=3)
        else:
            display.draw_string(100, y, "OUT", color=WHITE, size=3)

def light_flash(pins, times, interval=100):
    state = False
    for _ in range(times * 2):
        state = not state
        for pin in pins:
            pin.value(state)
        utime.sleep_ms(interval)

def wait_button_release(button):
    expected = 1 if button in (UP, DOWN, TEMP) else 0
    while button.value() == expected:
        utime.sleep_ms(10)

def slot_machine():
    # 使用元组代替命名元组
    # 索引: 0=name, 1=prob, 2=mult, 3=color, 4=size
    SYMBOLS = (
        ("A", 0.3, 2, st7789.BLUE, 5),
        ("B", 0.25, 3, st7789.BLUE, 5),
        ("C", 0.2, 4, st7789.BLUE, 5),
        ("D", 0.15, 5, st7789.BLUE, 5),
        ("S", 0.07, 10, st7789.MAGENTA, 6),
        ("SS", 0.025, 20, st7789.YELLOW, 7),
        ("SSS", 0.005, 50, st7789.RED, 10)
    )
    
    # 预计算累积概率以提高性能
    cum_probs = []
    cum_prob = 0
    for symbol in SYMBOLS:
        cum_prob += symbol[1]  # prob
        cum_probs.append(cum_prob)
    
    balance = 100
    anim_pos = 0
    last_update = 0
    
    def input_bet():
        current_bet = 0
        keypad = [['7','8','9'], ['4','5','6'], ['1','2','3'], ['Yes','0','<-']]
        selected_row, selected_col = 1, 1
        
        def draw_interface():
            display.fill(BLACK)
            display.draw_string(50, 10, "Balance:$%.2f" % balance, color=WHITE, size=2)
            display.rect(20, 50, 200, 40, WHITE)

            if current_bet:
                text_width = len(str(current_bet)) * 6 * 3
                x_pos = (240 - text_width) // 2
                display.draw_string(x_pos, 60, str(current_bet), color=WHITE, size=3)
            
            for r, row in enumerate(keypad):
                for c, key in enumerate(row):
                    x, y = c*80+10, r*40+100
                    if r == selected_row and c == selected_col:
                        display.fill_rect(x, y, 60, 30, WHITE)
                        display.draw_string(x+10, y+5, key, color=BLACK, size=2)
                    else:
                        display.rect(x, y, 60, 30, WHITE)
                        display.draw_string(x+10, y+5, key, color=WHITE, size=2)
        
        draw_interface()
        
        while True:
            if LEFT.value() == 0:
                selected_col = (selected_col - 1) % 3
                draw_interface()
                wait_button_release(LEFT)
            elif RIGHT.value() == 0:
                selected_col = (selected_col + 1) % 3
                draw_interface()
                wait_button_release(RIGHT)
            elif UP.value() == 1:
                selected_row = (selected_row - 1) % 4
                draw_interface()
                wait_button_release(UP)
            elif DOWN.value() == 1:
                selected_row = (selected_row + 1) % 4
                draw_interface()
                wait_button_release(DOWN)
            elif TEMP.value() == 1:
                key = keypad[selected_row][selected_col]
                
                if key in '0123456789':
                    current_bet = current_bet*10+int(key)
                elif key == '<-':
                    current_bet = current_bet//10
                elif key == 'Yes':
                    if current_bet == 0:
                        return 0
                    
                    if 0.1 <= current_bet <= balance:
                        return current_bet
                    else:
                        display.fill(BLACK)
                        display.draw_string(10, 100, "Invalid bet!", color=st7789.RED, size=4)
                        utime.sleep(1)
                        current_bet = 0
                
                draw_interface()
                wait_button_release(TEMP)
            
            utime.sleep_ms(10)
    
    def show_result(result):
        light_flash(pinArray[:3], 5)
        
        display.fill(BLACK)
        display.draw_string(0, 0, "Game", color=st7789.RED, bg=BLACK, size=6, vertical=True)
        display.draw_string(50, 0, "Start", color=st7789.RED, bg=BLACK, size=6, vertical=True)
        
        # 显示符号表
        for i, symbol in enumerate(SYMBOLS):
            display.draw_string(110, 35*i, "%s:%d" % (symbol[0], symbol[2]), color=symbol[3], bg=BLACK, size=4)
        
        for pin in pinArray[:3]:
            pin.on()
        utime.sleep(1)
        
        display.fill(BLACK)
        start_time = utime.ticks_ms()
        
        # 简化动画显示
        positions = [40, 100, 160]
        symbols_to_draw = []
        
        # 预查找符号属性
        for symbol_name in result:
            for s in SYMBOLS:
                if s[0] == symbol_name:  # name
                    symbols_to_draw.append(s)
                    break
        
        # 等待1秒后显示结果
        while utime.ticks_diff(utime.ticks_ms(), start_time) < 1000:
            utime.sleep_ms(50)
        
        # 直接显示结果
        for i, symbol in enumerate(symbols_to_draw):
            text_width = len(symbol[0]) * 6 * symbol[4]  # name and size
            x = positions[i] - text_width // 2
            display.draw_string(x, 100, symbol[0], color=symbol[3], bg=BLACK, size=symbol[4])
        
        utime.sleep(2)
        
        for pin in pinArray[:3]:
            pin.off()
    
    try:
        while balance >= 1:
            bet = input_bet()
            if bet == 0: 
                break
            
            balance -= bet
            
            # 生成结果
            result = []
            for _ in range(3):
                rand_val = urandom.random()
                for i, cum_prob in enumerate(cum_probs):
                    if rand_val <= cum_prob:
                        result.append(SYMBOLS[i][0])  # name
                        break
            
            show_result(result)
            
            payout = 0
            
            if result[0] == result[1] == result[2]:
                for symbol in SYMBOLS:
                    if symbol[0] == result[0]:  # name
                        payout = bet * symbol[2]  # mult
                        break
            
            elif result[0] == result[1] or result[1] == result[2] or result[0] == result[2]:
                payout = bet * 1.5
            
            display.fill(BLACK)
            if payout > 0:
                display.draw_string(30, 100, "Win:$%.2f" % payout, color=st7789.GREEN, bg=BLACK, size=4)
            else:
                display.draw_string(50, 100, "No Win", color=st7789.RED, bg=BLAC, size=4)
            utime.sleep(2)
        
        display.fill(BLACK)
        if balance > 100:
            msg = "You win!"
        elif balance == 100:
            msg = "Break even!"
        else:
            msg = "Try again!"
        
        display.draw_string(15, 100, msg, color=st7789.YELLOW, bg=BLACK, size=4)
        utime.sleep(2)
    finally:
        # 确保在退出时释放内存
        gc.collect()

# 十连抽游戏
def ten_draw():
    # 使用元组代替命名元组
    # 索引: 0=name, 1=min_val, 2=max_val, 3=prob, 4=counter_threshold, 5=color
    prizes = (
        ("RED", 30, 1000, 0.005, None, st7789.RED),
        ("YELLOW", 5, 30, 0.03, 120, st7789.YELLOW),
        ("MAGENTA", 0.5, 5, 0.1, 10, st7789.MAGENTA),
        ("BLUE", 0.1, 0.5, None, None, st7789.BLUE)
    )
    
    # 预计算累积概率
    cum_probs = []
    cum_prob = 0
    for prize in prizes:
        if prize[3] is not None:  # prob
            cum_prob += prize[3]
            cum_probs.append(cum_prob)
    
    balance = 100.0
    draw_cost = 10
    counters = [0, 0]  # 黄色和紫色计数器
    
    try:
        while balance >= draw_cost:
            display.fill(BLACK)
            display.draw_string(50, 30, "Balance:", color=WHITE, size=3)
            display.draw_string(50, 60, "$%.2f" % balance, color=WHITE, size=3)
            display.draw_string(50, 110, "in", color=st7789.YELLOW, size=3)
            display.draw_string(170, 110, "out", color=st7789.YELLOW, size=3)
            
            while True:
                if TEMP.value() == 1:
                    wait_button_release(TEMP)
                    break
                elif DOWN.value() == 1:
                    wait_button_release(DOWN)
                    return
                utime.sleep_ms(10)
            
            balance -= draw_cost
            total_winnings = 0
            results = []
            
            for _ in range(10):
                counters[0] += 1
                counters[1] += 1
                
                prize = None
                if counters[0] >= prizes[1][4]:  # YELLOW counter_threshold
                    prize = prizes[1]
                    counters = [0, 0]
                elif counters[1] >= prizes[2][4]:  # MAGENTA counter_threshold
                    prize = prizes[2]
                    counters[1] = 0
                
                if not prize:
                    rand_val = urandom.random()
                    for i, cum_prob in enumerate(cum_probs):
                        if rand_val <= cum_prob:
                            prize = prizes[i]
                            break
                    
                    if not prize:
                        prize = prizes[3]
                
                amount = urandom.uniform(prize[1], prize[2])  # min_val, max_val
                amount = round(amount, 2)
                total_winnings += amount
                results.append((prize[0], amount, prize[5]))  # name, amount, color

            display.fill(BLACK)
            display.draw_string(50, 10, "Results:", color=WHITE, size=3)
            
            # 分批显示结果以节省内存
            for i in range(0, min(5, len(results))):
                name, amt, color = results[i]
                display.draw_string(20, 40+i*20, "%s:$%.2f" % (name, amt), color=color, bg=BLACK, size=2)
            
            utime.sleep(1)
            
            if len(results) > 5:
                display.fill(BLACK)
                display.draw_string(50, 10, "Results:", color=WHITE, size=3)
                for i in range(5, min(10, len(results))):
                    name, amt, color = results[i]
                    display.draw_string(20, 40+(i-5)*20, "%s:$%.2f" % (name, amt), color=color, bg=BLACK, size=2)
                utime.sleep(1)
            
            display.fill(BLACK)
            display.draw_string(10, 100, "Total:$%.2f" % total_winnings, color=st7789.GREEN, bg=BLACK, size=3)
            balance += total_winnings
            utime.sleep(1)
        
        display.fill(BLACK)
        display.draw_string(50, 100, "Game Over!", color=st7789.RED, bg=BLACK, size=4)
        utime.sleep(2)
    finally:
        gc.collect()

# 大转盘游戏
def mode3_csgo_style():
    # 使用元组代替命名元组
    # 索引: 0=name, 1=color, 2=prob, 3=min_val, 4=max_val
    prizes = (
        ("AWP", st7789.RED, 0.01, 100, 1000),
        ("AK-47", st7789.color565(255, 215, 0), 0.05, 30, 100),
        ("M4A1", st7789.MAGENTA, 0.1, 5, 30),
        ("MAC-10", st7789.BLUE, 0.2, 0.5, 5),
        ("usp", st7789.GREEN, 0.64, 0.1, 0.5)
    )
    
    # 预计算累积概率
    cum_probs = []
    cum_prob = 0
    for prize in prizes:
        cum_prob += prize[2]  # prob
        cum_probs.append(cum_prob)
    
    def select_prize():
        rand_val = urandom.random()
        for i, cum_prob in enumerate(cum_probs):
            if rand_val <= cum_prob:
                value = urandom.uniform(prizes[i][3], prizes[i][4])  # min_val, max_val
                return prizes[i], value
        value = urandom.uniform(prizes[-1][3], prizes[-1][4])
        return prizes[-1], value
    
    block_size = 48
    block_gap = 2
    block_border = 2
    y_pos = 80
    screen_width = 240
    
    initial_speed = 40
    min_speed = 0.2
    
    balance = 100.0
    cost_per_box = 10
    
    try:
        while balance >= cost_per_box:
            display.fill(BLACK)
            display.draw_string(10, 30, "Balance:$%.2f" % balance, color=WHITE, size=3)
            display.draw_string(40, 180, "Press TEMP", color=st7789.YELLOW, size=3)
            
            key_pressed = False
            while not key_pressed:
                if TEMP.value() == 1:
                    wait_button_release(TEMP)
                    key_pressed = True
                elif DOWN.value() == 1:
                    wait_button_release(DOWN)
                    return
            
            balance -= cost_per_box
            
            # 目标奖品（实际未使用）
            target_prize = select_prize()
            block_queue = [select_prize() for _ in range(5)]
            current_x = 0
            
            start_time = utime.ticks_ms()
            constant_phase = True
            decel_start = 0
            
            # 预计算动画参数
            constant_speed_time = urandom.randint(6000, 8000)
            deceleration_time = urandom.randint(3000, 5000)
            
            while True:
                current_time = utime.ticks_ms()
                elapsed = utime.ticks_diff(current_time, start_time)
                
                if constant_phase and elapsed < constant_speed_time:
                    speed = initial_speed
                elif constant_phase:
                    constant_phase = False
                    decel_start = current_time
                    speed = initial_speed
                elif elapsed < constant_speed_time + deceleration_time:
                    progress = min(1.0, utime.ticks_diff(current_time, decel_start) / deceleration_time)
                    speed = max(min_speed, initial_speed * (1 - progress)**3)
                else:
                    speed = 0
                    break
                
                current_x -= speed
                
                if current_x <= -block_size:
                    current_x += block_size + block_gap
                    block_queue.pop(0)
                    block_queue.append(select_prize())
                
                display.fill(BLACK)
                
                for i in range(5):
                    block_x = int(current_x) + i * (block_size + block_gap)
                    draw_x = max(0, block_x)
                    draw_width = min(block_size, screen_width - draw_x)
                    
                    if draw_width > 0:
                        prize, value = block_queue[i]
                        src_x_offset = max(0, -block_x)
                        
                        display.fill_rect(draw_x, y_pos, draw_width, block_size, WHITE)
                        display.fill_rect(
                            draw_x + block_border - src_x_offset, 
                            y_pos + block_border,
                            draw_width - 2 * block_border + src_x_offset, 
                            block_size - 2 * block_border,
                            prize[1]  # color
                        )
                
                display.fill_rect(screen_width // 2 - 1, y_pos - 15, 3, block_size + 30, WHITE)
                utime.sleep_ms(40)
            
            display.fill(BLACK)
            
            for i in range(5):
                block_x = int(current_x) + i * (block_size + block_gap)
                prize, value = block_queue[i]
                display.fill_rect(block_x, y_pos, block_size, block_size, WHITE)
                display.fill_rect(
                    block_x + block_border,
                    y_pos + block_border,
                    block_size - 2 * block_border,
                    block_size - 2 * block_border,
                    prize[1]  # color
                )
            
            display.fill_rect(screen_width // 2 - 1, y_pos - 15, 3, block_size + 30, WHITE)
            
            center_block_index = (screen_width // 2 - int(current_x)) // (block_size + block_gap)
            result_prize, result_value = block_queue[center_block_index]
            
            for _ in range(4):
                selected_x = int(current_x) + center_block_index * (block_size + block_gap)
                display.fill_rect(
                    selected_x + block_border,
                    y_pos + block_border,
                    block_size - 2 * block_border,
                    block_size - 2 * block_border,
                    WHITE
                )
                utime.sleep_ms(200)
                display.fill_rect(
                    selected_x + block_border,
                    y_pos + block_border,
                    block_size - 2 * block_border,
                    block_size - 2 * block_border,
                    result_prize[1]  # color
                )
                utime.sleep_ms(200)
            
            display.fill(BLACK)
            display.draw_string(30, 50, "You won:", color=WHITE, size=4)
            display.draw_string(50, 110, "$%.2f" % result_value, color=result_prize[1], bg=BLACK, size=3)
            display.draw_string(10, 180, "Balance:$%.2f" % balance, color=WHITE, size=3)
            
            balance += result_value
            utime.sleep(3)
        
        display.fill(BLACK)
        display.draw_string(10, 100, "Insufficient Funds!", color=st7789.RED, size=4)
        utime.sleep(2)
    finally:
        gc.collect()

# 主菜单
def main_menu():
    selection = 0
    options = ["1", "2", "3"]
    draw_menu("selection", options, selection)
    
    while True:
        if LEFT.value() == 0:
            selection = (selection - 1) % 3
            wait_button_release(LEFT)
            draw_menu("selection", options, selection)
        elif RIGHT.value() == 0:
            selection = (selection + 1) % 3
            wait_button_release(RIGHT)
            draw_menu("selection", options, selection)
        elif DOWN.value() == 1:
            selection = 3
            wait_button_release(DOWN)
            draw_menu("selection", options, selection)
        elif UP.value() == 1:
            selection = 0
            wait_button_release(UP)
            draw_menu("selection", options, selection)
        elif TEMP.value() == 1:
            wait_button_release(TEMP)
            return selection + 1 if selection < 3 else 4
        
        utime.sleep_ms(10)

# 主程序
gc.enable()  # 启用垃圾回收

while True:
    mode = main_menu()
    
    if mode == 1:
        slot_machine()
    elif mode == 2:
        ten_draw()
    elif mode == 3:
        mode3_csgo_style()
    elif mode == 4:
        break
    
    display.fill(BLACK)
    gc.collect()  # 每次游戏结束后回收内存